package mil.af.amc.adpetracker.dao.hibernate;

import mil.af.amc.adpetracker.dao.GenericDao;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

/**
 * Generic DAO extended by all other Hibernate DAOs
 *
 * @author TSgt Jason Ferguson
 */
public class HibernateGenericDao<T> implements GenericDao<T> {
//public class HibernateGenericDao<T> extends HibernateDaoSupport implements GenericDao<T> {

    private static final Log log = LogFactory.getLog(HibernateGenericDao.class);

    private Class<T> type;

    public HibernateGenericDao(Class<T> type) {
        this.type = type;
    }

    protected SessionFactory sessionFactory;

    @Autowired
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }



    @SuppressWarnings({"unchecked", "UnnecessaryLocalVariable"})
    public T getById(final int id) {

        T results = null;

        Criteria genericCriteria = null;
        try {
            genericCriteria = sessionFactory.getCurrentSession().createCriteria(type);
            genericCriteria.add(Restrictions.eq("id", id));
            results = (T) genericCriteria.uniqueResult();

            return results;
        } catch (HibernateException e) {
            log.debug("getById() threw HibernateException." , e);
        }

        return results;
//        return (T) genericCriteria.uniqueResult();
//        T results = null;
//        try {
//            results = (T) getHibernateTemplate().execute(new HibernateCallback() {
//                public Object doInHibernate(Session session) throws HibernateException, SQLException {
//
//                    Criteria crit = session.createCriteria(type);
//                    crit.add(Restrictions.eq("id", id));
//                    return crit.uniqueResult();
//
//                }
//            });
//        } catch (DataAccessException e) {
//
//            log.debug("getById() threw DataAccessException." , e);
//            return null;
//        }

        //getHibernateTemplate().initialize(results);

//        return results;

    }

    public List<T> getAll() {

        Criteria genericCriteria = sessionFactory.getCurrentSession().createCriteria(type);
        return genericCriteria.list();
//        List<T> results = null;
//        try {
//            results = (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
//                public Object doInHibernate(Session session) throws HibernateException, SQLException {
//
//                    Criteria crit = session.createCriteria(type);
//                    return crit.list();
//                }
//            });
//        } catch (DataAccessException e) {
//            e.printStackTrace();
//        }
//
//        return results;
    }

    public int getCount() {

        Criteria genericCriteria = sessionFactory.getCurrentSession().createCriteria(type);
        genericCriteria.setProjection(Projections.rowCount());
        return (Integer) genericCriteria.uniqueResult();
//        return (Integer) getHibernateTemplate().execute(new HibernateCallback() {
//            public Object doInHibernate(Session session) throws HibernateException, SQLException {
//
//                Criteria crit = session.createCriteria(type);
//                crit.setProjection(Projections.rowCount());
//                return crit.uniqueResult();
//            }
//        });
    }

    public void delete(T persistentObject) {
        sessionFactory.getCurrentSession().delete(persistentObject);
        //getHibernateTemplate().delete(persistentObject);
    }


    public void saveOrUpdate(T object) {

        try {
            sessionFactory.getCurrentSession().saveOrUpdate(object);
        } catch (HibernateException e) {
            log.debug("saveOrUpdate() threw HibernateException", e);
        }

    }

    public T save(T object) {
        Integer id = (Integer) sessionFactory.getCurrentSession().save(object);

        T result = (T) sessionFactory.getCurrentSession().load(type, id);

        return result;
    }

//    public void save(T object) {
//
//        try {
//            getHibernateTemplate().save(object);
//        } catch (DataAccessException e) {
//            e.printStackTrace();
//
//        }
//    }

//    @SuppressWarnings("unchecked")
//    public Integer add(T object) {
//
//        try {
//            return (Integer) getHibernateTemplate().save(object);
//        } catch (DataAccessException e) {
//            System.out.println("DATA ACCESS EXCEPTION!!!");
//            e.printStackTrace();
//            return null;
//        }
//    }

    @SuppressWarnings("unchecked")
    public T merge(T object) {

        return (T) sessionFactory.getCurrentSession().merge(object);
        //return (T) getHibernateTemplate().merge(object);
    }

    @SuppressWarnings({"unchecked"})
    public List<T> getByQbe(T object) {

        Example example = Example.create(object);

        return (List<T>) sessionFactory.getCurrentSession().createCriteria(type).add(example).list();
//        genericCriteria.add(example);
//
//        return (List<T>) sessionFactory.getCurrentSession().
//
//        DetachedCriteria crit = DetachedCriteria.forClass(type);
//        Example e = Example.create(object);
//        crit.add(e);
//
//        return (List<T>) getHibernateTemplate().findByCriteria(crit);

//        return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
//            public Object doInHibernate(Session session) throws HibernateException, SQLException {
//
//                Criteria crit = session.createCriteria(new Class<T>().getClass());
//                throw new UnsupportedOperationException();
//            }
//        });
        //return (List<T>) getHibernateTemplate().findByExample(object);
    }
}
